%!Tex Program = xelatex
%\documentclass[a4paper]{article}
\documentclass[a4paper]{ctexart}
\usepackage{xltxtra}
\usepackage{listings}
\usepackage{float}
\usepackage{graphicx} % 导入graphicx宏包
\usepackage{geometry}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{enumitem}
\geometry{a4paper,scale=0.75}
\title{四则混合计算器的实现}
\author{周川迪}
\begin{document}
\maketitle
\section{简述}
main.cpp的代码是一个简单的表达式计算器。它通过扫描输入的表达式并进行语法检查，剔除无效字符，然后计算表达式的值。

以下是代码中的主要部分：
\begin{itemize}
    \item isoperator(char ch)函数用于判断字符是否为运算符。
    \item scan(string exp)函数用于扫描表达式、剔除无效字符、检查有无错误并在合适位置添加一些$0$，能组成合法的中缀表达式则返回处理后的表达式，不能组成则返回错误信息。
    \item Binary\_calc(double num1, char opt, double num2)函数用于执行二元运算。
    \item calculate(string exp)函数用于计算合法表达式的值，并输出结果。
    \item operate(string exp)函数对扫描后的结果进行操作，若为错误信息则输出，若为合法表达式则跳转calculate函数进行计算
    \item main()函数是程序的入口，从文件中读取表达式并进行处理。
\end{itemize}

\section{程序的设计思路}
\subsection{处理表达式}
新建一个字符串，储存处理后的表达式。

表达式中的有效符号只有数字、小数点、左右括号、加减和乘除（除法是“$/$”），不是这些符号的直接忽略。

如果是这些符号，分类讨论判断前一个有效符号（字符串里上一个进入的元素）与当前符号的搭配是否合理，若不合理则返回错误信息，若合理则将其存入字符串。合适的情况下给小数点前面（比如一般的计算器里，$.9$可以表示$0.9$），或表示正负的“+”或“-”前面加上一个0，使计算器能够以二元运算的形式处理。同时还判断“一个数字中有多个小数点”和括号不匹配的情况。

检测到不能组成合法的中缀表达式时，scan函数直接返回E，operate函数接收到该信息就会输出“Error.”

如能组成，处理后的表达式就变成了一个合法的中缀表达式，进入operate函数后转入calculate函数进行计算。

\subsection{计算过程}
使用了栈的数据结构，开了一个运算符栈和一个数字栈，在一些地方开了临时运算符栈和临时数字栈。

计算过程主要有以下四块内容。我进行了一点自己思考的创新，没有使用中缀表达式转后缀表达式的方法。
\subsubsection{数字处理}
使用state变量记录上一个表达式字符是运算符还是数，是整数部分还是小数部分，将各位数字进行合理的求和，在遇到运算符时能够合理地分离。得到当前的完整数字currentNum，放入数字栈中。
\subsubsection{读入加减乘除运算符}
初始用prior数组记录了运算符优先级。

我希望运算符栈中的运算符优先级递增。

读到一个运算符，把运算符栈栈顶优先级比它高的一系列相同优先级的运算符和对应的数字移动到临时栈中（这样可以保证从左到右计算），这一系列计算最左边的数字保留在数字栈栈顶。

然后数字栈栈顶和临时数字栈栈顶各弹出一个数字，临时运算符栈栈顶弹出一个运算符，将二元运算结果放回数字栈顶。

重复以上步骤直到当前读到的运算符放进运算符栈后，保持运算符栈中的运算符优先级递增。

（该想法在加入乘方等一更高优先级的二元运算时也成立，注意栈顶的更高优先级要“一层一层”地消去）
\subsubsection{处理括号}
左括号直接放进运算符栈。

读入右括号，像上一步的方法那样，计算出对应左括号之后所有东西的结果，结果放到数字栈栈顶，弹出左括号。
\subsubsection{读完表达式之后}
如果表达式不以右括号结尾，将currentNum放入数字栈中。

然后按照处理括号的方法，把剩下的计算全部完成，最终的结果就是整个表达式的值。将其输出。

\subsection{关于程序的其他}
\begin{itemize}
    \item 由于程序所使用的string和STL的stack能够自动释放内存，所以不会有内存泄漏。
    \item 程序本身是标准输入输出，只输入一行表达式，输出对应结果。使用run脚本实现多组数据的输入输出。
    \item 使用了using namespace std; 减小了代码量。
\end{itemize}

\section{测试说明}

将多组数据一行一行的放在input.txt中，用run脚本实现把每行的输入对应的输出在output中产生。

数据构建来自于给的样例，和制造的一些复杂情况，比如小数、先乘除后加减、多重括号等。

复制到计算器中得到标准结果后再加入需要剔除的无效字符。

\end{document}